#include "game_application.h"
#include "game_log.h"
#include "game_ev.h"
#include <unistd.h>
#include <signal.h>
#include <libunwind.h>
#include <cxxabi.h>
#include "game_curl.h"
#include "game_macros.h"
#include "game_autorelease.h"
#include "game_util.h"


void sigsegv_handler(int sig, siginfo_t *info, void *secret)
{
  // show backtrace
  unw_cursor_t cursor; unw_context_t uc;
  unw_word_t ip, sp;
  unw_getcontext(&uc);
  unw_init_local(&cursor, &uc);
  while (unw_step(&cursor) > 0) {
    unw_word_t  offset, pc;
    char fname[64];
    fname[0] = '\0';
    unw_get_reg(&cursor, UNW_REG_IP, &pc);
    (void) unw_get_proc_name(&cursor, fname, sizeof(fname), &offset);
    C_LOG("%p: (%s+0x%x) [%s]", pc, fname, offset, abi::__cxa_demangle(fname, NULL, NULL, NULL));
  }

  struct sigaction act;
  sigemptyset(&act.sa_mask);
  act.sa_flags = SA_NODEFER | SA_ONSTACK | SA_RESETHAND;
  act.sa_handler = SIG_DFL;
  sigaction(sig, &act, NULL);
  kill(getpid(),sig);
}

CGameApplication::CGameApplication():_delay(0){

}

UINT64 CGameApplication::getDelay(){
  return _delay;
}

void CGameApplication::run(){
  run(40);
};

void CGameApplication::run(mseconds_t ms){
  _delta = ms;
  do{
    UINT64 _now = __get_time_ms();
    UINT64 delay = 0;
    event_base_loop(_evbase, EVLOOP_NONBLOCK);
    doRun();
    g_CGameAutorelease.release();
    delay = __get_time_ms() - _now;
    if(delay > ms){
      _delay = delay;
      C_WARN("Performance time greater than delta.");
      continue;
    }else{
      _delay = ms;
      ::usleep((ms - delay) * 1000);
    }
    // *((uint8_t*)(0x0)) = 1; // segv error test
    // ::usleep(_delta * 1000);
  }while(!_shutdown);
}

void CGameApplication::shutdown(){
  _shutdown = TRUE;
}

BOOL CGameApplication::init(event_base* evbase){

  do{
    _evbase = evbase;

    struct sigaction act;
    sigemptyset(&act.sa_mask);
    act.sa_flags = SA_NODEFER | SA_ONSTACK | SA_RESETHAND | SA_SIGINFO;
    act.sa_sigaction = sigsegv_handler;
    sigaction(SIGSEGV, &act, NULL);

    CC_BREAK_IF(!g_CGameCurl.init());

    return TRUE;
  }while(true);
  return FALSE;
  
}

BOOL CGameApplication::init(){
  return init(g_CGameEV.getBase());
}
